/* -*-C-*-
 ##############################################################################
 #
 # File:        trice/src/timing.c
 # RCS:         "@(#)$Revision: 1.15 $ $Date: 94/03/09 11:17:37 $"
 # Description: Routines for configuring timing parameters on a E1430 module.
 # Author:      Doug Passey
 # Created:     
 # Language:    C
 # Package:     E1430
 # Status:      "@(#)$State: Exp $"
 #
 # (C) Copyright 1992, Hewlett-Packard Company, all rights reserved.
 #
 ##############################################################################
 #
 # Please add additional comments here
 #
 # Revisions:
 #
 ##############################################################################
*/

#    include <stdio.h>

#include "trice.h"
#include "err1430.h"


#ifndef lint
const char i1430_timing_fileId[] = "$Header: timing.c,v 1.15 94/03/09 11:17:37 chriss Exp $";
#endif


/*****************************************************************************
 *
 * Clears the masters array.
 *
 ****************************************************************************/
void i1430_clear_masters_array(void)
{
  int i;

  for(i=0; i<MAX_MAINFRAMES; i++) {
    e1430_masters[i] = -1;
  }
}


/*****************************************************************************
 *
 * Return in <bitsPtr> the register bits associated with <multisync>.
 * Returns 0 if all ok, else return negative error number.
 *
 ****************************************************************************/
SHORTSIZ16 i1430_get_multi_sync_bits(SHORTSIZ16 multisync, SHORTSIZ16 *bitsPtr)
{
  switch(multisync) {
    case E1430_MULTI_SYNC_ON:
      *bitsPtr = TIMING_SETUP_MULTI_SYNC_ON;
      break;
    case E1430_MULTI_SYNC_OFF:
      *bitsPtr = TIMING_SETUP_MULTI_SYNC_OFF;
      break;
    default:
      return (i1430_Error(ERR1430_ILLEGAL_MULTI_SYNC_MODE, NULL, NULL));
  }

  return (0);
}


/*****************************************************************************
 *
 * Return in <bitsPtr> the register bits associated with <adcClock>.
 * Returns 0 if all ok, else return negative error number.
 *
 ****************************************************************************/
static SHORTSIZ16 get_adc_clock_source_bits(SHORTSIZ16 adcClock, SHORTSIZ16 *bitsPtr)
{
  switch(adcClock) {
    case E1430_ADC_CLOCK_INTERNAL:
      *bitsPtr = TIMING_SETUP_ADC_CLOCK_INTERNAL;
      break;
    case E1430_ADC_CLOCK_EXTERNAL:
      *bitsPtr = TIMING_SETUP_ADC_CLOCK_EXTERNAL;
      break;
    default:
      return (i1430_Error(ERR1430_ILLEGAL_ADC_CLOCK_SOURCE, NULL, NULL));
  }

  return (0);
}


/*****************************************************************************
 *
 * Return in <bitsPtr> the register bits associated with <dspClock>.
 * Returns 0 if all ok, else return negative error number.
 *
 ****************************************************************************/
static SHORTSIZ16 get_dsp_clock_source_bits(SHORTSIZ16 dspClock, SHORTSIZ16 *bitsPtr)
{
  switch(dspClock) {
    case E1430_DSP_CLOCK_ADC:
      *bitsPtr = TIMING_SETUP_DSP_CLOCK_ADC;
      break;
    case E1430_DSP_CLOCK_INTERNAL:
      *bitsPtr = TIMING_SETUP_DSP_CLOCK_INTERNAL;
      break;
    default:
      return (i1430_Error(ERR1430_ILLEGAL_DSP_CLOCK_SOURCE, NULL, NULL));
  }

  return (0);
}


/*****************************************************************************
 * Set the clock sources for a group of modules <groupID>.  
 * Returns 0 if all ok, else return negative error number.
 ****************************************************************************/
SHORTSIZ16 e1430_set_clock_mode(SHORTSIZ16 groupID, SHORTSIZ16 multiSync,
			SHORTSIZ16 adcClock, SHORTSIZ16 dspClock)
{
  SHORTSIZ16 modSetupBits, bits;
  SHORTSIZ16 error;
  SHORTSIZ16 mask;

  /* get bit equivalent of these clock setup parameters */
  error = i1430_get_multi_sync_bits(multiSync, &bits);
  if(error) return (error);
  modSetupBits = bits;

  error = get_adc_clock_source_bits(adcClock, &bits);
  if(error) return (error);
  modSetupBits |= bits;

  error = get_dsp_clock_source_bits(dspClock, &bits);
  if(error) return (error);
  modSetupBits |= bits;

  mask = TIMING_SETUP_MULTI_SYNC_MASK & TIMING_SETUP_ADC_CLOCK_MASK
					& TIMING_SETUP_DSP_CLOCK_MASK;

  error = i1430_update_group_module_bits(groupID, E1430_TIMING_SETUP_REG,
					mask, modSetupBits);
 
  e1430_pause(0.1);

  return (error);
}

/*****************************************************************************
 *
 * Sets the module at <la> to
 * source or not source its ADC clock on the backplane depending on <state>.
 * Returns 0 if all ok, else return negative error number.
 *
 ****************************************************************************/
SHORTSIZ16 e1430_set_clock_master_mode(SHORTSIZ16 la, SHORTSIZ16 state)
{
  SHORTSIZ16 reg;
  SHORTSIZ16 error;
  SHORTSIZ16 mainframe; 	/* mainframe number */
  SHORTSIZ16 index;

  error = i1430_get_index_from_la(la, &index);
  if(error) return(error);

  mainframe = e1430_modStates[index].cage;

  error = e1430_read_register_image(la, E1430_TIMING_SETUP_REG, &reg); 
  if(error) return(error);

  reg &= TIMING_SETUP_MASTER_MASK;
  switch(state) {
    case E1430_MASTER_CLOCK_ON:
      if(e1430_masters[mainframe] != -1) {		/* if already master here */
	if(e1430_masters[mainframe] != la) {
          return (i1430_Error(ERR1430_ONLY_ONE_MASTER, NULL, NULL));
	}
      }else{
        e1430_masters[mainframe] = la ;
      }
      reg |= TIMING_SETUP_MASTER_ON;
      break;
    case E1430_MASTER_CLOCK_OFF:
      reg |= TIMING_SETUP_MASTER_OFF;
      e1430_masters[mainframe] =  -1;
      break;
    default:
      return(i1430_Error(ERR1430_ILLEGAL_CLOCK_MASTER_MODE, NULL, NULL));
  }

  error = e1430_write_register_image(la, E1430_TIMING_SETUP_REG, reg);
  if(error) return(error);

/*printf("end: e1430_masters[%hd] = %hd\n", mainframe, e1430_masters[mainframe]);*/
  return (0);
}


/*****************************************************************************
 *
 * Gets the state of master clock mode in the module at <la>
 * Returns 0 if all ok, else return negative error number.
 *
 ****************************************************************************/
SHORTSIZ16 e1430_get_clock_master_mode(SHORTSIZ16 la, SHORTSIZ16 *state)
{
  SHORTSIZ16 error, reg;

  error = e1430_read_register_image(la, E1430_TIMING_SETUP_REG, &reg); 
  if(error) return(error);

  reg &= ~TIMING_SETUP_MASTER_MASK;
  if(reg == TIMING_SETUP_MASTER_ON) {
    *state = E1430_MASTER_CLOCK_ON;
  }else{
    *state = E1430_MASTER_CLOCK_OFF;
  }

  return(0);
}
  
/*****************************************************************************
 *
 * Sets the DSP clock source in <groupID> to <source>.
 * Returns 0 if all ok, else return negative error number.
 *
 ****************************************************************************/
SHORTSIZ16 e1430_set_dsp_clock(SHORTSIZ16 groupID, SHORTSIZ16 source)
{
  SHORTSIZ16 bits;
  SHORTSIZ16 error;

  error = get_dsp_clock_source_bits(source, &bits);
  if(error) return (error);

  error = i1430_update_group_module_bits(groupID, E1430_TIMING_SETUP_REG,
					TIMING_SETUP_DSP_CLOCK_MASK, bits);
 
  e1430_pause(0.1);

  return (error);
}


/*****************************************************************************
 *
 * Sets the ADC clock source in <groupID> to <source>.
 * Returns 0 if all ok, else return negative error number.
 *
 ****************************************************************************/
SHORTSIZ16 e1430_set_adc_clock(SHORTSIZ16 groupID, SHORTSIZ16 source)
{
  SHORTSIZ16 bits;
  SHORTSIZ16 error;

  error = get_adc_clock_source_bits(source, &bits);
  if(error) return (error);

  error = i1430_update_group_module_bits(groupID, E1430_TIMING_SETUP_REG,
					TIMING_SETUP_ADC_CLOCK_MASK, bits);
 
  e1430_pause(0.1);

  return (error);
}


/*****************************************************************************
 *
 * Sets the multi sync state in <groupID> to <state>.
 * Returns 0 if all ok, else return negative error number.
 *
 ****************************************************************************/
SHORTSIZ16 e1430_set_multi_sync(SHORTSIZ16 groupID, SHORTSIZ16 state)
{
  SHORTSIZ16 bits;
  SHORTSIZ16 error;

  error = i1430_get_multi_sync_bits(state, &bits);
  if(error) return (error);

  return (i1430_update_group_module_bits(groupID, E1430_TIMING_SETUP_REG,
					TIMING_SETUP_MULTI_SYNC_MASK, bits));
}


/*****************************************************************************
 *
 * Sets the Track only bit in the Timing Setup register in the modules in 
 * <groupID> to <state>.
 * Returns 0 if all ok, else return negative error number.
 *
 ****************************************************************************/
SHORTSIZ16 e1430_set_track_only(SHORTSIZ16 groupID, SHORTSIZ16 state)
{
  SHORTSIZ16 bits;

  if(state) {
    bits = TIMING_SETUP_TRACKING_ON;
  }else{
    bits = TIMING_SETUP_TRACKING_OFF;
  }

  return (i1430_update_group_module_bits(groupID, E1430_TIMING_SETUP_REG,
					TIMING_SETUP_TRACKING_MASK, bits));
}


/*****************************************************************************
 *
 * Returns sync state of module at <index> in the e1430_modStates array.
 * Returns 0 if all ok, else return negative error number.
 *
 ****************************************************************************/
SHORTSIZ16 i1430_get_sync_state_index(SHORTSIZ16 index)
{
  switch(e1430_modStates[index].timingSetup & ~TIMING_SETUP_MULTI_SYNC_MASK) {
    case TIMING_SETUP_MULTI_SYNC_ON:
      return (E1430_MULTI_SYNC_ON);
    case TIMING_SETUP_MULTI_SYNC_OFF:
      return (E1430_MULTI_SYNC_OFF);
    default:
      return (i1430_Error(ERR1430_ILLEGAL_MULTI_SYNC_MODE, NULL, NULL));
  }
}


/*****************************************************************************
 *
 * Returns the multi sync state of the module group, <groupID>, into
 * the variable pointed to by <statePtr>.  
 * Returns 0 if OK, returns ERR1430_PARAMETER_UNEQUAL if the source is
 * not the same for all modules in the group.
 *
 ****************************************************************************/
SHORTSIZ16 e1430_get_multi_sync(SHORTSIZ16 groupID, SHORTSIZ16 *statePtr)
{ 
  return (i1430_get_short_parm(groupID, i1430_get_sync_state_index, 
				"multi sync state", statePtr));
}
 

/*****************************************************************************
 *
 * Returns sync line of module at <index> in the e1430_modStates array.
 * Returns 0 if all ok, else return negative error number.
 *
 ****************************************************************************/
SHORTSIZ16 i1430_get_sync_line_index(SHORTSIZ16 index)
{
  switch(e1430_modStates[index].measControl & ~MEAS_CONTROL_SYNC_MASK) {
    case MEAS_CONTROL_SYNC_ON:
      return (E1430_SYNC_LINE_LOW);
    case MEAS_CONTROL_SYNC_OFF:
      return (E1430_SYNC_LINE_HIGH);
    default:
      return (i1430_Error(ERR1430_ILLEGAL_SYNC_LINE_STATE, NULL, NULL));
  }
}
  
/*****************************************************************************
 *
 * Returns ADC clock source module at <index> in the e1430_modStates array.
 * Returns 0 if all ok, else return negative error number.
 *
 ****************************************************************************/
SHORTSIZ16 i1430_get_adc_clock_index(SHORTSIZ16 index)
{
  switch(e1430_modStates[index].timingSetup & ~TIMING_SETUP_ADC_CLOCK_MASK) {
    case TIMING_SETUP_ADC_CLOCK_INTERNAL:
      return (E1430_ADC_CLOCK_INTERNAL);
    case TIMING_SETUP_ADC_CLOCK_EXTERNAL:
      return (E1430_ADC_CLOCK_EXTERNAL);
    default:
      return (i1430_Error(ERR1430_ILLEGAL_ADC_CLOCK_SOURCE, NULL, NULL));
  }
}
  

/*****************************************************************************
 *
 * Returns the ADC clock source of the module group, <groupID>, into
 * the variable pointed to by <sourcePtr>.  
 * Returns 0 if OK, returns ERR1430_PARAMETER_UNEQUAL if the source is
 * not the same for all modules in the group.
 *
 ****************************************************************************/
SHORTSIZ16 e1430_get_adc_clock(SHORTSIZ16 groupID, SHORTSIZ16 *sourcePtr)
{ 
  return (i1430_get_short_parm(groupID, i1430_get_adc_clock_index, 
				"ADC clock source", sourcePtr));
}
 

/*****************************************************************************
 *
 * Returns DSP clock source module at <index> in the e1430_modStates array.
 * Returns 0 if all ok, else return negative error number.
 *
 ****************************************************************************/
SHORTSIZ16 i1430_get_dsp_clock_index(SHORTSIZ16 index)
{
  switch(e1430_modStates[index].timingSetup & ~TIMING_SETUP_DSP_CLOCK_MASK) {
    case TIMING_SETUP_DSP_CLOCK_INTERNAL:
      return (E1430_DSP_CLOCK_INTERNAL);
    case TIMING_SETUP_DSP_CLOCK_ADC:
      return (E1430_DSP_CLOCK_ADC);
    default:
      return (i1430_Error(ERR1430_ILLEGAL_DSP_CLOCK_SOURCE, NULL, NULL));
  }
}


/*****************************************************************************
 *
 * Returns the DSP clock source of the module group, <groupID>, into
 * the variable pointed to by <sourcePtr>.  
 * Returns 0 if OK, returns ERR1430_PARAMETER_UNEQUAL if the source is
 * not the same for all modules in the group.
 *
 ****************************************************************************/
SHORTSIZ16 e1430_get_dsp_clock(SHORTSIZ16 groupID, SHORTSIZ16 *sourcePtr)
{ 
  return (i1430_get_short_parm(groupID, i1430_get_dsp_clock_index, 
				"DSP clock source", sourcePtr));
}
 

